package com.talkweb.ncfw.intercept;

import java.lang.reflect.Method;
import java.util.Date;

import net.sf.json.util.PropertyFilter;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import com.talkweb.ncfw.annotation.OperateLog;
import com.talkweb.ncfw.component.log.entity.SysOperateLog;
import com.talkweb.ncfw.component.log.service.ILogService;
import com.talkweb.ncfw.component.log.task.WriteSysOperateLogTask;
import com.talkweb.ncfw.component.rights.entity.User;
import com.talkweb.ncfw.data.IUserSession;
import com.talkweb.ncfw.data.OperateResult;
import com.talkweb.ncfw.data.OperateType;
import com.talkweb.ncfw.security.SecurityHelper;
import com.talkweb.ncfw.utils.AssertUtils;
import com.talkweb.ncfw.utils.PKUtils;
import com.talkweb.ncfw.utils.PropertiesUtils;
import com.talkweb.ncfw.utils.StringUtils;
import com.talkweb.ncfw.web.utils.json.JsonUtils;

/**
 * <p>文件名称: WriteOperateLogInterceptor.java</p>
 * <p>文件描述: 记录系统操作日志拦截器</p>
 * <p>版权所有: 版权所有(C)2010</p>
 * <p>公　　司: 拓维信息系统股份有限公司</p>
 * <p>内容摘要: 简要描述本文件的内容，包括主要模块、函数及能的说明</p>
 * <p>其他说明: 其它内容的说明</p>
 * <p>完成日期: 2011-4-11</p>
 * <p>修改记录1:</p>
 * <pre>
 *    修改日期:
 *    修 改 人:
 *    修改内容:
 * </pre>
 * <p>修改记录2：…</p>
 * @author  Wuqingming
 */
public class WriteOperateLogInterceptor implements MethodInterceptor, InitializingBean {
	
	/** 日志服务 */
	private ILogService logService;
	
	/** 任务线程池 */
	private ThreadPoolTaskExecutor taskExecutor;

	/** 操作结果信息路径 */
	private String operateResultMsgPath;

	public ILogService getLogService() {
		return logService;
	}

	public void setLogService(ILogService logService) {
		this.logService = logService;
	}

	public ThreadPoolTaskExecutor getTaskExecutor() {
		return taskExecutor;
	}

	public void setTaskExecutor(ThreadPoolTaskExecutor taskExecutor) {
		this.taskExecutor = taskExecutor;
	}

	public String getOperateResultMsgPath() {
		return operateResultMsgPath;
	}

	public void setOperateResultMsgPath(String operateResultMsgPath) {
		this.operateResultMsgPath = operateResultMsgPath;
	}

	public void afterPropertiesSet() throws Exception {
		AssertUtils.notNull(logService, "logService can not be null.");
		AssertUtils.notNull(taskExecutor, "taskExecutor can not be null.");
	}

	public Object invoke(MethodInvocation invocation) throws Throwable {
		Method targetMethod 		= invocation.getMethod();			//目标方法
		Object[] methodParameters 	= invocation.getArguments();		//方法参数
		String remark				= null;								//备注
		Date excuteBeginTime		= null;								//方法执行-开始时间
		Date excuteEndTime			= null;								//方法执行-结束时间
		String operateResult		= null;								//方法执行-结果
		Object returnObject			= null;								//方法执行-返回结果
		try {
			excuteBeginTime 		= new Date();
			returnObject 			= invocation.proceed();				//执行目标方法
			operateResult			= OperateResult.SUCCESS;			//成功
		} catch (Throwable throwable) {
			operateResult 			= OperateResult.FAILURE;			//异常
			remark					= throwable.getMessage();
			throw throwable;
		} finally {
			//判断方法是否采用了日志注解
			OperateLog operateLog 	= targetMethod.getAnnotation(OperateLog.class);
			if (operateLog == null) {
				return returnObject;
			}
			if (!this.checkIfNeedLog(operateLog.module())) {//不需要记录日志
				return returnObject;
			}
			excuteEndTime 			= new Date();
			SysOperateLog sysOperateLog = new SysOperateLog();
			sysOperateLog.setLogId(PKUtils.getPrimaryKey());
			sysOperateLog.setOperateType(operateLog.operateType());
			sysOperateLog.setBeginTime(excuteBeginTime);
			sysOperateLog.setEndTime(excuteEndTime);
			
			if (returnObject != null && operateResult.equals(OperateResult.SUCCESS)) {
				if (returnObject instanceof Number
						|| returnObject instanceof Boolean
						|| returnObject instanceof String) {
					if (returnObject.toString().length() <= 30) {
						sysOperateLog.setResultCode(returnObject.toString());		//设置结果代码
						if (operateResultMsgPath != null) {
							String key = new StringBuilder(operateLog.module()).append(".")
								.append(targetMethod.getName()).append(".")
								.append(returnObject.toString()).toString();
							String operateResultMsg = PropertiesUtils.getProperty(operateResultMsgPath , key);
							if (StringUtils.isNotEmpty(operateResultMsg)) {
								remark = operateResultMsg;
							}
						}
					}
					if (!(returnObject instanceof Boolean) && !StringUtils.isEmpty(operateLog.successCode()) 
							&& !StringUtils.equals(returnObject.toString(), operateLog.successCode())) {
						operateResult = OperateResult.FAILURE;
					}
					if (returnObject instanceof Boolean && !Boolean.parseBoolean(returnObject.toString())) {
						operateResult = OperateResult.FAILURE;
					}
				}
			}
			sysOperateLog.setOperateResult(operateResult);
			sysOperateLog.setModule(operateLog.module());
			sysOperateLog.setClassName(targetMethod.getDeclaringClass().getName());
			sysOperateLog.setMethodName(targetMethod.getName());
			if (!operateLog.ignoreParam() && methodParameters != null && methodParameters.length > 0) {//不忽略参数
				sysOperateLog.setMethodParameters(getParameterStr(targetMethod, methodParameters));
			}
			sysOperateLog.setMethodDescription(operateLog.description());
			sysOperateLog.setRemark(remark);
			
			String operator 	= null;
			String operatorName = null;
			IUserSession userSession = SecurityHelper.getCurrentUser();
			if (userSession != null) {
				operator		= userSession.getUserid();
				operatorName 	= userSession.getUsername();
			}
			sysOperateLog.setOperator(operator);
			sysOperateLog.setOperatorName(operatorName);
			this.writeLog(sysOperateLog);
		}
		return returnObject;
	}
	
	/**
	 * 
	 * @author：Wuqingming 	        
	 * @date：2011-11-24
	 * @Description：获取参数字符串
	 * @param parameters
	 * @param operateLog
	 * @return
	 */
	private String getParameterStr (Method targetMethod, Object[] parameters) {
		OperateLog operateLog 	= targetMethod.getAnnotation(OperateLog.class);
		if (parameters == null || parameters.length == 0) {
			return null;
		}
		StringBuilder methodParams = new StringBuilder();
		boolean isUserUpdate = StringUtils.indexOfAny(operateLog.operateType(), new String[]{OperateType.ADD, OperateType.UPDATE}) > -1;
		PropertyFilter valuePropertyFilter = null;
		if (isUserUpdate && targetMethod.getName().equalsIgnoreCase("updatePassword")) {//为修改密码
			methodParams.append("[").append(parameters[0]).append(",").append("******").append("]");
		} else {
			if (isUserUpdate && StringUtils.inArrayIgnoreCase(targetMethod.getName(), new String[]{"addUser", "updateUser"})) {
				valuePropertyFilter = new PropertyFilter() {
					public boolean apply(Object source, String name, Object value) {
						return (value == null || name.equals("password"));
					}
				};
			} else {
				valuePropertyFilter = new PropertyFilter() {
					public boolean apply(Object source, String name, Object value) {
						return value == null;
					}
				};
			}
			methodParams.append(JsonUtils.getJSONStringByFilter(parameters, valuePropertyFilter));
		}
		int paramMaxLen = 3800;
		String resultStr = methodParams.length() > paramMaxLen ? methodParams.substring(0, paramMaxLen)
				: methodParams.toString();
		return resultStr;
	}
	
	public static void main (String[] args) {
		User user = new User ();
		user.setUserId("0123120312312");
		user.setPassword("000000");
		Object[] parameters = {"0123120312312", "000000", user};
		PropertyFilter valuePropertyFilter = new PropertyFilter() {
			public boolean apply(Object source, String name, Object value) {
				System.out.println(name);
				return true;
			}
		};
		String str = JsonUtils.getJSONStringByFilter(parameters, valuePropertyFilter);
		System.out.println(str);
	}
	
	/**
	 * 
	 * @author：Wuqingming 	        
	 * @date：2011-11-8
	 * @Description：检测是否需要记录日志
	 * @param module 模块名称
	 * @return
	 */
	private boolean checkIfNeedLog (String module) {
		String modules = PropertiesUtils.getProperty("operatelog.modules");
		if (!StringUtils.isEmpty(modules)) {
			String[] moduleArray = modules.split(",");
			for (String _module : moduleArray) {
				if (StringUtils.equals(_module, module)) {
					return true;
				}
			}
		}
		return false;
	}
	
	private void writeLog (SysOperateLog sysOperateLog) {
		WriteSysOperateLogTask writeSysOperateLogTask = new WriteSysOperateLogTask(this.logService, sysOperateLog);
		this.taskExecutor.execute(writeSysOperateLogTask);
	}

}

